home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / internet / other / mail / pathalia.zoo / src / parse.y < prev    next >
Encoding:
Lex Description  |  1991-01-12  |  11.2 KB  |  545 lines

  1. %{
  2. /* pathalias -- by steve bellovin, as told to peter honeyman */
  3. #ifndef lint
  4. static char    *sccsid = "@(#)parse.y    9.10 88/09/07";
  5. #endif /* lint */
  6.  
  7. #include "def.h"
  8.  
  9. /* scanner states (yylex, parse) */
  10. #define OTHER        0
  11. #define COSTING        1
  12. #define NEWLINE        2
  13. #define FILENAME    3
  14.  
  15. /* exports */
  16. long Tcount;
  17. extern void yyerror();
  18.  
  19. /* imports */
  20. extern node *addnode(), *addprivate();
  21. extern void fixprivate(), alias(), deadlink(), deletelink();
  22. extern link *addlink();
  23. extern int strcmp();
  24. extern char *strsave();
  25. extern int optind;
  26. extern char *Cfile, *Netchars, **Argv;
  27. extern int Lineno, Argc;
  28.  
  29. /* privates */
  30. STATIC void fixnet(), adjust();
  31. STATIC int yylex(), yywrap(), getword();
  32. static int Scanstate = NEWLINE;    /* scanner (yylex) state */
  33. int Donelast = 0;    /* we're all out of files to parse */
  34.  
  35. /* flags for ys_flags */
  36. #define TERMINAL 1
  37. %}
  38.  
  39. %union {
  40.     node    *y_node;
  41.     Cost    y_cost;
  42.     char    y_net;
  43.     char    *y_name;
  44.     struct {
  45.         node *ys_node;
  46.         Cost ys_cost;
  47.         short ys_flag;
  48.         char ys_net;
  49.         char ys_dir;
  50.     } y_s;
  51. }
  52.  
  53. %type <y_s>    site asite
  54. %type <y_node>    links aliases plist network nlist host nhost
  55. %type <y_node>    usite delem dlist
  56. %type <y_cost>    cost cexpr
  57.  
  58. %token <y_name>    SITE HOST STRING
  59. %token <y_cost>    COST
  60. %token <y_net>    NET
  61. %token EOL PRIVATE DEAD DELETE FILETOK ADJUST
  62.  
  63. %left    '+' '-'
  64. %left    '*' '/'
  65.  
  66. %%
  67. map    :    /* empty */
  68.     |    map        EOL
  69.     |    map links    EOL
  70.     |    map aliases    EOL
  71.     |    map network    EOL
  72.     |    map private    EOL
  73.     |    map dead    EOL
  74.     |    map delete    EOL
  75.     |    map file    EOL
  76.     |    map adjust    EOL
  77.     |    error        EOL
  78.     ;
  79.  
  80. links    : host site cost {
  81.         struct link *l;
  82.  
  83.         l = addlink($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir);
  84.         if (GATEWAYED($2.ys_node))
  85.             l->l_flag |= LGATEWAY;
  86.         if ($2.ys_flag & TERMINAL)
  87.             l->l_flag |= LTERMINAL;
  88.       }            
  89.     | links ',' site cost {
  90.         struct link *l;
  91.  
  92.         l = addlink($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir);
  93.         if (GATEWAYED($3.ys_node))
  94.             l->l_flag |= LGATEWAY;
  95.         if ($3.ys_flag & TERMINAL)
  96.             l->l_flag |= LTERMINAL;
  97.       }
  98.     | links ','    /* benign error */
  99.     ;
  100.  
  101. host    : HOST        {$$ = addnode($1);}
  102.     | PRIVATE    {$$ = addnode("private");}
  103.     | DEAD        {$$ = addnode("dead");}
  104.     | DELETE    {$$ = addnode("delete");}
  105.     | FILETOK    {$$ = addnode("file");}
  106.     | ADJUST    {$$ = addnode("adjust");}
  107.     ;
  108.  
  109. site    : asite {
  110.         $$ = $1;
  111.         $$.ys_net = DEFNET;
  112.         $$.ys_dir = DEFDIR;
  113.       }
  114.     | NET asite {
  115.         $$ = $2;
  116.         $$.ys_net = $1;
  117.         $$.ys_dir = LRIGHT;
  118.       }
  119.     | asite NET {
  120.         $$ = $1;
  121.         $$.ys_net = $2;
  122.         $$.ys_dir = LLEFT;
  123.       }
  124.     ;
  125.  
  126. asite    : SITE {
  127.         $$.ys_node = addnode($1);
  128.         $$.ys_flag = 0;
  129.       }
  130.     | '<' SITE '>' {
  131.         Tcount++;
  132.         $$.ys_node = addnode($2);
  133.         $$.ys_flag = TERMINAL;
  134.       }
  135.     ;
  136.  
  137. aliases    : host '=' SITE    {alias($1, addnode($3));}
  138.     | aliases ',' SITE    {alias($1, addnode($3));}
  139.     | aliases ','    /* benign error */
  140.     ;
  141.  
  142. network    : nhost '{' nlist '}' cost    {fixnet($1, $3, $5, DEFNET, DEFDIR);}
  143.     | nhost NET '{' nlist '}' cost    {fixnet($1, $4, $6, $2, LRIGHT);}
  144.     | nhost '{' nlist '}' NET cost    {fixnet($1, $3, $6, $5, LLEFT);}
  145.     ;
  146.  
  147. nhost    : '='        {$$ = 0;    /* anonymous net */}
  148.     | host '='    {$$ = $1;    /* named net */}
  149.     ;
  150.  
  151. nlist    : SITE        {$$ = addnode($1);}
  152.     | nlist ',' SITE {
  153.         node *n;
  154.  
  155.         n = addnode($3);
  156.         if (n->n_net == 0) {
  157.             n->n_net = $1;
  158.             $$ = n;
  159.         }
  160.       }
  161.     | nlist ','    /* benign error */
  162.     ;
  163.         
  164. private    : PRIVATE '{' plist '}'            /* list of privates */
  165.     | PRIVATE '{' '}'    {fixprivate();}    /* end scope of privates */
  166.     ;
  167.  
  168. plist    : SITE            {addprivate($1)->n_flag |= ISPRIVATE;}
  169.     | plist ',' SITE    {addprivate($3)->n_flag |= ISPRIVATE;}
  170.     | plist ','        /* benign error */
  171.     ;
  172.  
  173. dead    : DEAD '{' dlist '}';
  174.  
  175. dlist    : delem
  176.     | dlist ',' delem
  177.     | dlist ','        /* benign error */
  178.     ;
  179.  
  180. delem    : SITE            {deadlink(addnode($1), (node *) 0);}
  181.     | usite NET usite    {deadlink($1, $3);}
  182.     ;
  183.  
  184. usite    : SITE    {$$ = addnode($1);} ;    /* necessary unit production */
  185.  
  186. delete    : DELETE '{' dellist '}';
  187.  
  188. dellist    : delelem
  189.     | dellist ',' delelem
  190.     | dellist ','        /* benign error */
  191.     ;
  192.  
  193. delelem    : SITE {
  194.         node *n;
  195.  
  196.         n = addnode($1);
  197.         deletelink(n, (node *) 0);
  198.         n->n_flag |= ISPRIVATE;
  199.       }
  200.     | usite NET usite    {deletelink($1, $3);}
  201.     ;
  202.  
  203. file    : FILETOK '{' {Scanstate = FILENAME;} STRING {Scanstate = OTHER;} '}' {
  204.         Lineno = 0;
  205.         Cfile = strsave($4);
  206.     }
  207.  
  208. adjust    : ADJUST '{' adjlist '}' ;
  209.  
  210. adjlist    : adjelem
  211.     | adjlist ',' adjelem
  212.     | adjlist ','        /* benign error */
  213.     ;
  214.  
  215. adjelem    : usite cost    {adjust($1, $2);} ;
  216.  
  217. cost    : {$$ = DEFCOST;    /* empty -- cost is always optional */}
  218.     | '(' {Scanstate = COSTING;} cexpr {Scanstate = OTHER;} ')'
  219.         {$$ = $3;}
  220.     ;
  221.  
  222. cexpr    : COST
  223.     | '-' cexpr      {$$ = -$2;}
  224.     | '(' cexpr ')'   {$$ = $2;}
  225.     | cexpr '+' cexpr {$$ = $1 + $3;}
  226.     | cexpr '-' cexpr {$$ = $1 - $3;}
  227.     | cexpr '*' cexpr {$$ = $1 * $3;}
  228.     | cexpr '/' cexpr {
  229.         if ($3 == 0)
  230.             yyerror("zero divisor\n");
  231.         else
  232.             $$ = $1 / $3;
  233.       }
  234.     ;
  235. %%
  236.  
  237. void
  238. #ifdef YYDEBUG
  239. /*VARARGS1*/
  240. yyerror(fmt, arg)
  241.     char *fmt, *arg;
  242. #else
  243. yyerror(s)
  244.     char *s;
  245. #endif
  246. {
  247.     /* a concession to bsd error(1) */
  248.     fprintf(stderr, "\"%s\", ", Cfile);
  249. #ifdef YYDEBUG
  250.     fprintf(stderr, "line %d: ", Lineno);
  251.     fprintf(stderr, fmt, arg);
  252.     putc('\n', stderr);
  253. #else
  254.     fprintf(stderr, "line %d: %s\n", Lineno, s);
  255. #endif
  256. }
  257.  
  258. /*
  259.  * patch in the costs of getting on/off the network.
  260.  *
  261.  * for each network member on netlist, add links:
  262.  *    network -> member    cost = 0;
  263.  *    member -> network    cost = parameter.
  264.  *
  265.  * if network and member both require gateways, assume network
  266.  * is a gateway to member (but not v.v., to avoid such travesties
  267.  * as topaz!seismo.css.gov.edu.rutgers).
  268.  *
  269.  * note that members can have varying costs to a network, by suitable
  270.  * multiple declarations.  this is a feechur, albeit a useless one.
  271.  */
  272. STATIC void
  273. fixnet(network, nlist, cost, netchar, netdir)
  274.     register node *network;
  275.     node *nlist;
  276.     Cost cost;
  277.     char netchar, netdir;
  278. {    register node *member, *nextnet;
  279.     link *l;
  280.     static int netanon = 0;
  281.     char anon[25];
  282.  
  283.     if (network == 0) {
  284.         sprintf(anon, "[unnamed net %d]", netanon++);
  285.         network = addnode(anon);
  286.     }
  287.     network->n_flag |= NNET;
  288.  
  289.     /* insert the links */
  290.     for (member = nlist ; member; member = nextnet) {
  291.  
  292.         /* network -> member, cost is 0 */
  293.         l = addlink(network, member, (Cost) 0, netchar, netdir);
  294.         if (GATEWAYED(network) && GATEWAYED(member))
  295.             l->l_flag |= LGATEWAY;
  296.  
  297.         /* member -> network, cost is parameter */
  298.         /* never ever ever crawl up from a domain*/
  299.         if (!ISADOMAIN(network))
  300.             (void) addlink(member, network, cost, netchar, netdir);
  301.  
  302.         nextnet = member->n_net;
  303.         member->n_net = 0;    /* clear for later use */
  304.     }
  305. }
  306.  
  307. /* scanner */
  308.  
  309. #define QUOTE '"'
  310. #define STR_EQ(s1, s2) (s1[2] == s2[2] && strcmp(s1, s2) == 0)
  311. #define NLRETURN() {Scanstate = NEWLINE; return EOL;}
  312.  
  313. static struct ctable {
  314.     char *cname;
  315.     Cost cval;
  316. } ctable[] = {
  317.     /* ordered by frequency of appearance in a "typical" dataset */
  318.     {"DIRECT", 200},
  319.     {"DEMAND", 300},
  320.     {"DAILY", 5000},
  321.     {"HOURLY", 500},
  322.     {"DEDICATED", 100},
  323.     {"EVENING", 2000},
  324.     {"LOCAL", 25},
  325.     {"LOW", 5},    /* baud rate, quality penalty */
  326.     {"DEAD", MILLION},
  327.     {"POLLED", 5000},
  328.     {"WEEKLY", 30000},
  329.     {"HIGH", -5},    /* baud rate, quality bonus */
  330.     {"FAST", -80},    /* high speed (>= 9.6 kbps) modem */
  331.     /* deprecated */
  332.     {"ARPA", 100},
  333.     {"DIALED", 300},
  334.     {0, 0}
  335. };
  336.  
  337. STATIC int
  338. yylex()
  339. {    static char retbuf[128];    /* for return to yacc part */
  340.     register int c;
  341.     register char *buf = retbuf;
  342.     register struct ctable *ct;
  343.     register Cost cost;
  344.     char errbuf[128];
  345.     
  346.     if( Donelast == -1 && yywrap() )
  347.         return EOF;
  348.  
  349.     if (Donelast || feof(stdin) && yywrap())
  350.         return EOF;
  351.  
  352.     /* count lines, skip over space and comments */
  353.     if ((c = getchar()) == EOF)
  354.         NLRETURN();
  355.     
  356. continuation:
  357.     while (c == ' ' || c == '\t')
  358.         if ((c = getchar()) == EOF)
  359.             NLRETURN();
  360.  
  361.     if (c == '#')
  362.         while ((c = getchar()) != '\n')
  363.             if (c == EOF)
  364.                 NLRETURN();
  365.  
  366.     /* scan token */
  367.     if (c == '\n') {
  368.         Lineno++;
  369.         if ((c = getchar()) != EOF) {
  370.             if (c == ' ' || c == '\t')
  371.                 goto continuation;
  372.             ungetc(c, stdin);
  373.         }
  374.         NLRETURN();
  375.     }
  376.  
  377.     switch(Scanstate) {
  378.     case COSTING:
  379.         if (isdigit(c)) {
  380.             cost = c - '0';
  381.             for (c = getchar(); isdigit(c); c = getchar())
  382.                 cost = (cost * 10) + c - '0';
  383.             ungetc(c, stdin);
  384.             yylval.y_cost = cost;
  385.             return COST;
  386.         }
  387.  
  388.         if (getword(buf, c) == 0) {
  389.             for (ct = ctable; ct->cname; ct++)
  390.                 if (STR_EQ(buf, ct->cname)) {
  391.                     yylval.y_cost = ct->cval;
  392.                     return COST;
  393.                 }
  394.             sprintf(errbuf, "unknown cost (%s), using default", buf);
  395.             yyerror(errbuf);
  396.             yylval.y_cost = DEFCOST;
  397.             return COST;
  398.         }
  399.  
  400.         return c;    /* pass the buck */
  401.  
  402.     case NEWLINE:
  403.         Scanstate = OTHER;
  404.         if (getword(buf, c) != 0)
  405.             return c;
  406.         /*
  407.          * special purpose tokens.
  408.          *
  409.          * the "switch" serves the dual-purpose of recognizing
  410.          * unquoted tokens only.
  411.          */
  412.         switch(c) {
  413.         case 'p':
  414.             if (STR_EQ(buf, "private"))
  415.                 return PRIVATE;
  416.             break;
  417.         case 'd':
  418.             if (STR_EQ(buf, "dead"))
  419.                 return DEAD;
  420.             if (STR_EQ(buf, "delete"))
  421.                 return DELETE;
  422.             break;
  423.         case 'f':
  424.             if (STR_EQ(buf, "file"))
  425.                 return FILETOK;
  426.             break;
  427.         case 'a':
  428.             if (STR_EQ(buf, "adjust"))
  429.                 return ADJUST;
  430.             break;
  431.         }
  432.  
  433.         yylval.y_name = buf;
  434.         return HOST;
  435.  
  436.     case FILENAME:
  437.         while (c != EOF && isprint(c)) {
  438.             if (c == ' ' || c == '\t' || c == '\n' || c == '}')
  439.                 break;
  440.             *buf++ = c;
  441.             c = getchar();
  442.         }
  443.         if (c != EOF)
  444.             ungetc(c, stdin);
  445.         *buf = 0;
  446.         yylval.y_name = retbuf;
  447.         return STRING;
  448.     }
  449.  
  450.     if (getword(buf, c) == 0) {
  451.         yylval.y_name = buf;
  452.         return SITE;
  453.     }
  454.  
  455.     if (index(Netchars, c)) {
  456.         yylval.y_net = c;
  457.         return NET;
  458.     }
  459.  
  460.     return c;
  461. }
  462.  
  463. /*
  464.  * fill str with the next word in [0-9A-Za-z][-._0-9A-Za-z]+ or a quoted
  465.  * string that contains no newline.  return -1 on failure or EOF, 0 o.w.
  466.  */ 
  467. STATIC int
  468. getword(str, c)
  469.     register char *str;
  470.     register int c;
  471. {
  472.     if (c == QUOTE) {
  473.         while ((c = getchar()) != QUOTE) {
  474.             if (c == '\n') {
  475.                 yyerror("newline in quoted string\n");
  476.                 ungetc(c, stdin);
  477.                 return -1;
  478.             }
  479.             if (c == EOF) {
  480.                 yyerror("EOF in quoted string\n");
  481.                 return -1;
  482.             }
  483.             *str++ = c;
  484.         }
  485.         *str = 0;
  486.         return 0;
  487.     }
  488.  
  489.     /* host name must start with alphanumeric or `.' */
  490.     if (!isalnum(c) && c != '.')
  491.         return -1;
  492.  
  493. yymore:
  494.     do {
  495.         *str++ = c;
  496.         c = getchar();
  497.     } while (isalnum(c) || c == '.' || c == '_');
  498.  
  499.     if (c == '-' && Scanstate != COSTING)
  500.         goto yymore;
  501.  
  502.     ungetc(c, stdin);
  503.     *str = 0;
  504.     return 0;
  505. }
  506.  
  507. STATIC int
  508. yywrap()
  509. {    char errbuf[100];
  510.  
  511.     fixprivate();    /* munge private host definitions */
  512.     Lineno = 1;
  513.     Donelast = 0;        /* we're not at the end of the list */
  514.     while (optind < Argc) {
  515.         if (freopen((Cfile = Argv[optind++]), "r", stdin) != 0)
  516.             return 0;
  517.         sprintf(errbuf, "%s: %s", Argv[0], Cfile);
  518.         perror(errbuf);
  519.     }
  520.     /* freopen(NULL_FILE, "r", stdin); */
  521.     Donelast=1;    /* so maybe we are, sue me */
  522.     return -1;
  523. }
  524.  
  525. STATIC void
  526. adjust(n, cost)
  527.     node *n;
  528.     Cost cost;
  529. {    link *l;
  530.  
  531.     n->n_cost += cost;    /* cumulative */
  532.  
  533.     /* hit existing links */
  534.     for (l = n->n_link; l; l = l->l_next) {
  535.         if ((l->l_cost += cost) < 0) {
  536.             char buf[100];
  537.  
  538.             l->l_flag |= LDEAD;
  539.             sprintf(buf, "link to %s deleted with negative cost",
  540.                             l->l_to->n_name);
  541.             yyerror(buf);
  542.         }
  543.     }
  544. }
  545.